﻿using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Xml.Serialization;

namespace Business.Logic
{
    /// <summary>
    /// Base64-sSerializer and encryptor
    /// </summary>
    public class ObjectStreamer
    {
        public static string EncKey = "kd8hznd92dbh45h1kd8h4nd92dbR45h8";
        public static string IV = "kd8h4nd92dbh45h8";

        /// <summary>
        /// Base 64 decodes, decrypts and deserializes the string
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="base64data"></param>
        /// <returns></returns>
        public static T StringToObject<T>(string base64data) 
        {
            string dataSer = DecryptBase64(base64data, EncKey);
            // Deserialize
            var ser = new XmlSerializer(typeof(T));
            T obj = (T)ser.Deserialize(new StringReader(dataSer));
            return obj;
        }

        /// <summary>
        /// XmlSerializes, encrypts and base64-encodes an object
        /// </summary>
        /// <param name="obj">Object</param>
        /// <returns>Base64-encoded string</returns>
        public static string ObjectToString(object obj)
        {
            // Serialize
            string xmlData = ObjectToXml(obj);
            // Encrypt and base encode
            string data64 = EncryptBase64(xmlData, EncKey);
            return data64;
        }

        /// <summary>
        /// XmlSerializes an object
        /// </summary>
        /// <param name="obj">Object</param>
        /// <returns>Base64-encoded string</returns>
        public static string ObjectToXml(object obj)
        {
            var sb = new StringBuilder();
            var sw = new StringWriter(sb);
            var type = obj.GetType();
            var ser = new XmlSerializer(type);
            ser.Serialize(sw, obj);
            return sw.ToString();
        }

        public static string EncryptBase64(string data, string key)
        {
            var rijndaelManaged = new RijndaelManaged();
            byte[] keyBytes = Encoding.UTF8.GetBytes(key);
            byte[] ivBytes = Encoding.UTF8.GetBytes(IV);
            byte[] dataBytes = Encoding.UTF8.GetBytes(data);
            var encryptor = rijndaelManaged.CreateEncryptor(keyBytes, ivBytes);

            var ms = new MemoryStream(data.Length * 5);
            var cryptoStream = new CryptoStream(ms, encryptor, CryptoStreamMode.Write);
            cryptoStream.Write(dataBytes, 0, dataBytes.Length);
            cryptoStream.Close();
            byte[] encDataBytes = ms.ToArray();
            ms.Dispose();
            // Base64-encode

            string base64 = Convert.ToBase64String(encDataBytes);
            return base64;
        }

        public static string DecryptBase64(string data, string key)
        {
            // Base64 decode

            var rijndaelManaged = new RijndaelManaged();
            byte[] keyBytes = Encoding.UTF8.GetBytes(key);
            byte[] ivBytes = Encoding.UTF8.GetBytes(IV);
            byte[] dataBytes = Convert.FromBase64String(data);
            var decryptor = rijndaelManaged.CreateDecryptor(keyBytes, ivBytes);

            var ms = new MemoryStream(data.Length * 5);
            ms.Write(dataBytes, 0, dataBytes.Length);
            ms.Seek(0, SeekOrigin.Begin);

            // decrypt
            byte[] outDataBytes = new byte[data.Length * 5];
            var cryptoStream = new CryptoStream(ms, decryptor, CryptoStreamMode.Read);
            int len = cryptoStream.Read(outDataBytes, 0, outDataBytes.Length);
            cryptoStream.Close();
            ms.Dispose();

            // return as string
            string outData = Encoding.UTF8.GetString(outDataBytes, 0, len);
            return outData;
        }
    }
}
